/**
*		@file BlkTable.cpp
*		@brief BlkTable class
*
*		@author KLM
*
*		@date 3/10/2012
*/
#include "BlkTable.h"
#include "QueryThread.h"

vector<BlkNode*>	BlkTable::vp_blknode_;
vector<BlkSet>		BlkTable::blk_next_table_;
vector<BlkSet>		BlkTable::blk_next_table_t_;

//build one blknode and push it into BlkTable
TNode* BlkTable::BuildBlkNode(TNode* current_tnode){
	BlkNode* current_blknode = NULL;

	current_blknode = new BlkNode();
	current_blknode->blk_idx = vp_blknode_.size()+1;
	current_blknode->blk_type = current_tnode->type;
	current_blknode->stmt_num_start = current_tnode->stmt_num;
	current_blknode->stmt_num_end = current_tnode->stmt_num;
	current_blknode->last_mod.resize(VarTable::GetSize());
	current_blknode->use_bef_mod.resize(VarTable::GetSize());
	current_blknode->next_a = NULL;
	current_blknode->next_b = NULL;
	
	StmtTable::SetStmtBlkNode(current_blknode->stmt_num_end,current_blknode);

	while(current_tnode->type == ASSIGN_TYPE){
		VarSet uses_vv = Uses::GetUsesS(current_tnode->stmt_num);
		for(int k = 0; k<uses_vv.size(); k++){
			if(uses_vv[k]==1&&current_blknode->last_mod[k]==0) 
				current_blknode->use_bef_mod[k].push_back(current_tnode->stmt_num);
		}
		VarSet modifies_vv = Modifies::GetModifiesS(current_tnode->stmt_num);
		for(int k = 0; k<modifies_vv.size(); k++){
			if(modifies_vv[k]==1){
				current_blknode->last_mod[k] = current_tnode->stmt_num;
				break;
			}
		}
		current_blknode->stmt_num_end = current_tnode->stmt_num;
		StmtTable::SetStmtBlkNode(current_blknode->stmt_num_end,current_blknode);
		if(current_tnode->right_sibling != NULL && current_tnode->right_sibling->type==ASSIGN_TYPE) 
			current_tnode = current_tnode->right_sibling;
		else break;
	}
	vp_blknode_.push_back(current_blknode);
	current_tnode = current_tnode->right_sibling;
	return current_tnode;
}

//build the table
void BlkTable::RebuildBlkTable(){
	BlkNode* current_blknode = NULL;
	TNode* current_tnode = NULL;

	//create blknodes
	for(int i = 1; i <= ProcTable::GetSize(); i++){
		current_tnode = ProcTable::GetProcASTRoot(i)->child->child;
		while(current_tnode != NULL)
			current_tnode = BuildBlkNode(current_tnode);
	}
	//create blknodes for the if tnodes and their-siblings
	for(int j = 1; j<=StmtTable::GetSizeIf();j++){
		TNode* current_tnode_L = NULL;
		TNode* current_tnode_R = NULL;

		current_tnode_L = StmtTable::GetIfTNode(j)->child->right_sibling->child;
		current_tnode_R = StmtTable::GetIfTNode(j)->child->right_sibling->right_sibling->child;
		while(current_tnode_L != NULL) 
			current_tnode_L = BuildBlkNode(current_tnode_L);
		while(current_tnode_R != NULL) 
			current_tnode_R = BuildBlkNode(current_tnode_R);
	}
	//create blknodes for the while tnodes and their right-siblings
	for(int k = 1; k<=StmtTable::GetSizeWhile(); k++){
		current_tnode = StmtTable::GetWhileTNode(k)->child->right_sibling->child;
		while(current_tnode != NULL) 
			current_tnode = BuildBlkNode(current_tnode);
	}
	//set next_a and next_b for all the blknodes
	for(int i = 0; i<vp_blknode_.size(); i++){
		if(StmtTable::GetStmtGNode(vp_blknode_[i]->stmt_num_end)->next_a != NULL)
			vp_blknode_[i]->next_a = StmtTable::GetStmtBlkNode(StmtTable::GetStmtGNode(vp_blknode_[i]->stmt_num_end)->next_a->stmt_num);
		if((vp_blknode_[i]->blk_type == IF_TYPE ||vp_blknode_[i]->blk_type == WHILE_TYPE)&&
			StmtTable::GetStmtGNode(vp_blknode_[i]->stmt_num_end)->next_b != NULL){
				vp_blknode_[i]->next_b = StmtTable::GetStmtBlkNode(StmtTable::GetStmtGNode(vp_blknode_[i]->stmt_num_end)->next_b->stmt_num);
		}
	}
	BuildBlkNextTable();
	BuildBlkNextTableT();
	BuildProcPathTable();
}

void BlkTable::BuildBlkNextTable(){
	blk_next_table_.resize(vp_blknode_.size());
	for(int i=0; i < BlkTable::GetSize();i++){
		blk_next_table_[i].resize(BlkTable::GetSize(), false);
	}
	for(int i = 0; i < BlkTable::GetSize(); i++){
		if(vp_blknode_[i]->next_a != NULL) blk_next_table_[i][vp_blknode_[i]->next_a->blk_idx - 1] = true;
		if(vp_blknode_[i]->next_b != NULL) blk_next_table_[i][vp_blknode_[i]->next_b->blk_idx - 1] = true;
	}
}

void BlkTable::BuildBlkNextTableT(){
	blk_next_table_t_.resize(vp_blknode_.size());
	for(int i = 0; i < BlkTable::GetSize(); i++){
		blk_next_table_t_[i].resize(BlkTable::GetSize(), false);
	}
	for(int i = 0; i < BlkTable::GetSize(); i++){
		for(int j = 0; j < BlkTable::GetSize(); j++){
			blk_next_table_t_[i][j] = blk_next_table_[j][i];
		}
	}

}

void BlkTable::BuildProcPathTable(){
	QueryThread::InitLock();
	ProcTable::InitProcPathTable();
	ProcSet temp_set_row;
	ProcSet temp_set_col;
	vector<ProcIdx> proc_idx_row;
	vector<ProcIdx> proc_idx_col;
	for( int i = 1; i<=ProcTable::GetSize(); i++ ){
		proc_idx_row.clear();
		temp_set_row = Calls::GetCallsAdvLeft(i);
		for( int k = 0; k<ProcTable::GetSize(); k++){
			if(temp_set_row[k]) proc_idx_row.push_back(k+1);
		}
		proc_idx_row.push_back(i);
		for( int j = 1; j<=ProcTable::GetSize(); j++ ){
			proc_idx_col.clear();
			temp_set_col = Calls::GetCallsAdvLeft(j);
			for( int k = 0; k<ProcTable::GetSize(); k++){
				if(temp_set_col[k]) proc_idx_col.push_back(k+1);
			}
			proc_idx_col.push_back(j);
			bool flag = false;
			for( int m = 0; m < proc_idx_row.size(); m++ ){
				for( int n = 0; n < proc_idx_col.size(); n++ ){
					for( int p = 1; p <= StmtTable::GetSizeCall(); p++ ){
						for( int q = 1; q <= StmtTable::GetSizeCall(); q++ ){
							if( proc_idx_row[m] == StmtTable::GetCallTNode(p)->value && 
								proc_idx_col[n] == StmtTable::GetCallTNode(q)->value){
									if(Next::IsNextAdv(StmtTable::GetCallTNode(p)->stmt_num,StmtTable::GetCallTNode(q)->stmt_num)){
										ProcTable::SetProcPath(i,j);
										flag = true;
										break;
									}
							}
						}
						if(flag) break;
					}
					if(flag) break;
				}
				if(flag) break;
			}
		}
	}
	QueryThread::DeleteLock();
}

string BlkTable::ToString(){
	stringstream output;
	//for( int i = 0; i < VarTable::GetSize(); i++ )
	//	output << "\t" << VarTable::GetVarName(i+1);
	//output << endl;
	//for( int i = 0; i < BlkTable::GetSize(); i++ )
	//{
	//	output << (i+1) << "[" << BlkTable::GetBlkNode(i+1)->stmt_num_start <<  "," << BlkTable::GetBlkNode(i+1)->stmt_num_end << "] ";
	//	for( int j = 0; j < VarTable::GetSize(); j++ )
	//		output << BlkTable::GetBlkNode(i+1)->last_mod[j] << "\t";
	//	output << endl << TNodeTypeToString(BlkTable::GetBlkNode(i+1)->blk_type) ;
	//	for( int j = 0; j < VarTable::GetSize(); j++ )
	//	{
	//		for( int k = 0; k < BlkTable::GetBlkNode(i+1)->use_bef_mod[j].size(); k++ )
	//			output << BlkTable::GetBlkNode(i+1)->use_bef_mod[j][k] << ",";
	//		output << "\t";
	//	}
	//	output << "->" << (BlkTable::GetBlkNode(i+1)->next_a == NULL ? 0 : BlkTable::GetBlkNode(i+1)->next_a->blk_idx);
	//	output << "->" << (BlkTable::GetBlkNode(i+1)->next_b == NULL ? 0 : BlkTable::GetBlkNode(i+1)->next_b->blk_idx);
	//	output << endl;
	//}
	//return output.str();


	for( int i = 1; i<=ProcTable::GetSize(); i++ ){
		for( int j = 1; j<=ProcTable::GetSize(); j++ ){
			if(ProcTable::IsProcPath(i,j)) cout<<"<"<<ProcTable::GetProcName(i)<<" "<<ProcTable::GetProcName(j)<<">"<<1<<" ";
			else cout<<"<"<<ProcTable::GetProcName(i)<<" "<<ProcTable::GetProcName(j)<<">"<<0<<" ";
		}
		cout<<endl;
	}

	string type = "";
	vector<BlkNode*> lst = BlkTable::vp_blknode_;
	
	for(int i=0; i<BlkTable::vp_blknode_.size();i++)
	{
		switch(lst[i]->blk_type){
		case 4: 
			type = "assgin";
			break;
		case 5: 
			type = "while";
			break;
		case 6: 
			type = "if";
			break;
		case 7: 
			type = "call";
			break;
		default:
			break;
		}

		output << lst[i]->blk_idx << "->" << type <<" ";
		if(lst[i]->stmt_num_start==lst[i]->stmt_num_end) 
			output << lst[i]->stmt_num_start<<" "<<endl;
		else 
			output << lst[i]->stmt_num_start << "-" << lst[i]->stmt_num_end << endl;
		if(lst[i]->next_a==NULL) output<< "0" <<" ";
		else{
			if(lst[i]->next_a->stmt_num_start==lst[i]->next_a->stmt_num_end) 
				output << lst[i]->next_a->stmt_num_start<<" ";
			else 
				output << lst[i]->next_a->stmt_num_start << "-" << lst[i]->next_a->stmt_num_end <<" ";
		}
		if(lst[i]->next_b==NULL&&(lst[i]->blk_type == ASSIGN_TYPE || lst[i]->blk_type == CALL_TYPE)) ;
		else if(lst[i]->next_b==NULL) output<< "0" <<" ";
		else {
			if(lst[i]->next_b->stmt_num_start==lst[i]->next_b->stmt_num_end) 
				output << lst[i]->next_b->stmt_num_start<<" ";
			else 
				output << lst[i]->next_b->stmt_num_start << "-" << lst[i]->next_b->stmt_num_end <<" ";
		}

		output << endl;
		output << "last modified"<<'\n';
		for(int j=0;j<VarTable::GetSize();j++){
			output << lst[i]->last_mod[j] << " ";
		}

		output << endl;
		output << "use before modifies"<<'\n';
		for(int j=0;j<VarTable::GetSize();j++){
			output << "<";
			for(int k=0; k<lst[i]->use_bef_mod[j].size();k++){
				if(k==0) output << lst[i]->use_bef_mod[j][k];
				else output <<" " << lst[i]->use_bef_mod[j][k];
			}
			output << "> ";
			
		}
		output << endl <<'\n';
	}
	
	return output.str();
}

BlkNode* BlkTable::GetBlkNode(BlkIdx blk_idx)
{
	return vp_blknode_[blk_idx - 1];
}

BlkSet& BlkTable::GetNextBlkRight(BlkIdx blk_idx)
{
	return blk_next_table_[blk_idx - 1];
}

BlkSet& BlkTable::GetNextBlkLeft(BlkIdx blk_idx)
{
	return blk_next_table_t_[blk_idx - 1];
}